package com.dhcc.bpm.common.segmentId;


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @description id生成服务获取
 * @author guogang
 * @date 2020年7月15日 上午9:01:27
 * @version 1.0.0
 * @version 1.0.1 添加数据库与curDate日期同步
 */
@Component
@EnableScheduling
public class LocalCacheIdGenerator {
	private static final Logger log = LoggerFactory.getLogger(LocalCacheIdGenerator.class);
	public static final int RETRY = 10; // 重试次数
	protected volatile SegmentId current;
	protected volatile SegmentId next;
	private volatile boolean isLoadingNext;
	private Object lock = new Object();
	private String bizType = "alarmNo";
	@Autowired
	private IdGeneratorService idGeneratorService;
	private ExecutorService executorService = Executors.newSingleThreadExecutor();
	private static IdGeneratorService idService;
	@PostConstruct
	void init() {
		loadCurrent();
		this.idService = idGeneratorService;
	}

	/**
	 * @description 获取id
	 * @date 2020年7月15日 上午9:34:33
	 * @return
	 */
	public String nextId() {
		int i = 0;
		while (i < RETRY) {
			if (current == null) {
				loadCurrent();
				i++;
				continue;
			}
			Result result = current.nextId();
			if (result.getCode() == ResultCode.OVER) {
				loadCurrent();
			} else {
				if (result.getCode() == ResultCode.LOADING) {
					loadNext();
				}
				return current.getCurDate() + String.format("%0" + current.getLen() + "d", result.getId());
			}
			i++;
		}
		throw new RuntimeException("获取 nextId 次数超出:" +RETRY+" !");
	}

	/**
	 * @description 加载当前分段
	 * @date 2020年7月15日 上午9:34:07
	 */
	public synchronized void loadCurrent() {
		if (current == null || !current.isUsed()) {
			if (next == null) {
				SegmentId segmentId = querySegmentId();
				this.current = segmentId;
			} else {
				current = next;
				next = null;
			}
		}
	}
	/**
	 * @description 查询分段
	 * @date 2020年7月15日 上午9:02:16
	 * @return SegmentId 分段id
	 */
	private SegmentId querySegmentId() {
		SegmentId segmentId = null;
		try {
			if(idGeneratorService == null){
				idGeneratorService = idService;
			}
			segmentId = idGeneratorService.nextSegmentId(bizType);
			if (segmentId != null) {
				return segmentId;
			}
		} catch (Exception e) {
			log.error("获取分段异常！！！", e);
			throw new RuntimeException(e);
		}
		throw new IllegalArgumentException("业务类型非法@" + bizType);
	}
	/**
	 * @description 同步数据库日期 每两分钟同步一次
	 * @date 2020年7月19日 上午9:03:22
	 */
	@Scheduled(cron = "0 0/2 * * * ?")
	void syncCurSegmentId() {
		SegmentId curSegmentId = idGeneratorService.getCurSegmentId(bizType);
		log.debug("curSegmentId[{}]", curSegmentId);
		if (curSegmentId.getCurDate().compareTo(curSegmentId.getNewDate()) <0) {
			log.error("current分段日期变动[{}][{}],分段失效", curSegmentId.getCurDate(),curSegmentId.getNewDate());
			current = null;
		}
		if (next != null && next.getCurDate().compareTo(curSegmentId.getNewDate())<0) {
			log.error("next日期变动[{}][{}],分段失效",  next.getCurDate(),next.getNewDate());
			next = null;
		}
	}

	/**
	 * @description 加载下一分段id
	 * @date 2020年7月15日 上午9:01:44
	 */
	public void loadNext() {
		if (next == null && !isLoadingNext) {
			synchronized (lock) {
				if (next == null && !isLoadingNext) {
					isLoadingNext = true;
					executorService.submit(new Runnable() {
						@Override
						public void run() {
							try {
								// 无论获取下个segmentId成功与否，都要将isLoadingNext赋值为false
								next = querySegmentId();
							} finally {
								isLoadingNext = false;
							}
						}
					});
				}
			}
		}
	}
}
